﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;

namespace Library.Util {
	public static class StringUtil {

		private const string AUniCode = "áảàạãâấẩầậẫăắẳằặẵ";
		private const string EUnicode = "éẻèẹẽêếểềệễ";
		private const string UUnicode = "úủùụũưứửừựữ";
		private const string IUnicode = "íỉìịĩ";
		private const string YUnicode = "ýỷỳỵỹ";
		private const string OUnicode = "óỏòọõơớởờợỡôốổồộỗ";
		private const string DUnicode = "đ";
		private const string EmailPattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-_]+\.[a-zA-Z]{2,4}$";
		private static readonly Dictionary<char, char> UnicodeDictionnary;
		static StringUtil() {
			UnicodeDictionnary = new Dictionary<char, char>();
			char[] values = { 'a', 'e', 'u', 'i', 'y', 'o', 'd' };
			string[] key = { AUniCode, EUnicode, UUnicode, IUnicode, YUnicode, OUnicode, DUnicode };
			for (int i = 0; i < values.Length; i++) {
				AddUnicodeKey(UnicodeDictionnary, key[i], values[i]);
				AddUnicodeKey(UnicodeDictionnary, key[i].ToUpper(), Char.ToUpper(values[i]));
			}
		}
		private static void AddUnicodeKey(Dictionary<char, char> dic, IEnumerable<char> key, char value) {
			foreach (char c in key) {
				dic.Add(c, value);
			}
		}

		public static int? ParseInt(this object obj) {
			if (obj == null) return null;
			return obj.ToString().ParseInt();
		}
		public static long? ParseLong(this object obj) {
			if (obj == null) return null;
			return obj.ToString().ParseLong();
		}

		public static int? ParseInt(this string str) {
			if (String.IsNullOrEmpty(str)) return null;
			int i;
			if (Int32.TryParse(str, out i)) {
				return i;
			}

			return null;
		}
		public static long? ParseLong(this string str) {
			if (String.IsNullOrEmpty(str)) return null;
			long i;
			if (Int64.TryParse(str, out i)) {
				return i;
			}

			return null;
		}
		public static DateTime? ParseDate(this string date, string format) {
			DateTime dateTime;
			if (DateTime.TryParse(date, out dateTime)) {
				return dateTime;
			}
			return null;
		}

		public static int ParseInt(this string str, int defaultValue) {
			var value = ParseInt(str);
			if (value.HasValue) return value.Value;
			return defaultValue;
		}

		public static string NullToEmpty(this string text) {
			if (text == null) return String.Empty;
			return text;
		}

		public static bool IsNullOrEmpty(this string text) {
			return String.IsNullOrEmpty(text);
		}

		public static string EmptyToNull(this string text) {
			if (text == String.Empty) return null;
			return text;
		}

		public static string XmlEncode(this string text) {
			if (text == null) {
				return String.Empty;
			}

			var textBuilder = new StringBuilder();
			foreach (char c in text) {
				switch (c) {
					case '"':
						textBuilder.Append("&quot;");
						break;
					case '\'':
						textBuilder.Append("&apos;");
						break;
					case '&':
						textBuilder.Append("&amp;");
						break;
					case '<':
						textBuilder.Append("&lt;");
						break;
					case '>':
						textBuilder.Append("&gt;");
						break;
					default:
						textBuilder.Append(c);
						break;
				}
			}

			return textBuilder.ToString();
		}

		public static string Md5Encrypt(this string plainText) {
			if (plainText.IsNullOrEmpty()) return String.Empty;
			var md5Hasher = new MD5CryptoServiceProvider();
			byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(plainText));

			var sBuilder = new StringBuilder();
			for (int i = 0; i < data.Length; i++) {
				sBuilder.Append(data[i].ToString("x2"));
			}

			return sBuilder.ToString();
		}
		public static bool IsValidEmail(this string email) {
			return IsValidEmail(email, EmailPattern);
		}

		public static bool IsValidEmail(this string email, string emailPattern) {
			if (String.IsNullOrEmpty(email)) {
				return false;
			}

			if (String.IsNullOrEmpty(emailPattern)) {
				return true;
			}

			if (!System.Text.RegularExpressions.Regex.IsMatch(email, emailPattern))
				return false;


			return true;
		}
		public static string RemoveUnicode(this string text) {
			if (String.IsNullOrEmpty(text)) return text;
			var nonUnicode = new StringBuilder();
			foreach (var c in text) {
				try {
					char nu;
					nonUnicode.Append(UnicodeDictionnary.TryGetValue(c, out nu) ? nu : c);
				} catch (ArgumentNullException) {
					nonUnicode.Append(c);
				}
			}

			return nonUnicode.ToString();
		}

		private static string VnOneNumber(char number) {
			switch (number) {
				case '0':
					return "không";
				case '1':
					return "một";//"@NNC199";
				case '2':
					return "hai";//"@NNC200";
				case '3':
					return "ba";//"@NNC201";
				case '4':
					return "bốn";//"@NNC202";
				case '5':
					return "năm";//"@NNC203";
				case '6':
					return "sáu";//"@NNC204";
				case '7':
					return "bảy";//"@NNC205";
				case '8':
					return "tám";//"@NNC206";
				case '9':
					return "chín";//"@NNC207";
				default:
					return String.Empty;//"@NNC208";
			}
		}

		private static string VnTwoNumber(string number) {
			var value = "mười";
			var first = number[0];
			var second = number[1];
			if (second == '0' && first != '1') {
				value = VnOneNumber(first) + " mươi";
			}
			switch (second) {
				case '0':
					break;
				case '1':
					if (first == '1') value = "mười một";
					else value = VnOneNumber(first) + " mươi mốt";
					break;
				case '5':
					if (first == '1') value = "mười lăm";
					else value = VnOneNumber(first) + " mươi lăm";
					break;
				default:
					if (first == '1') value = "mười " + VnOneNumber(second);
					else value = VnOneNumber(first) + " mươi " + VnOneNumber(second);
					break;

			}

			return value;
		}

		private static string VnThreeNumber(string number) {
			var first = number[0];
			var second = number[1];
			var third = number[2];
			string value;
			;
			if (number == "000") return String.Empty;
			if (second == '0') {
				if (third == '0') value = VnOneNumber(first) + " trăm";
				else value = VnOneNumber(first) + " trăm lẻ " + VnOneNumber(third);
			} else {
				value = VnOneNumber(first) + " trăm " + VnTwoNumber(second.ToString() + third);
			}

			return value.Trim();
		}
		private static string MultyNumber(string number, int len, int run) {
			var value = String.Empty;
			;
			while (len > 3) {
				string tmpAmount = number.Substring(number.Length - 3);
				if (tmpAmount != "000") {
					string tmp = VnThreeNumber(tmpAmount);
					value = tmp + " " + VnUnit(run) + " " + value;
				}

				number = number.Substring(0, number.Length - 3); //substr(number, 1, strlen(number) - 3);
				run++;
				if (run > 3) run = 1;
				if (len > 3) len = len - 3;
			}

			if (len == 1) value = VnOneNumber(number[0]) + " " + VnUnit(run) + " " + value;
			if (len == 2) value = VnTwoNumber(number) + " " + VnUnit(run) + " " + value;
			if (len == 3) value = VnThreeNumber(number) + " " + VnUnit(run) + " " + value;
			return value.Trim();
		}
		private static string VnUnit(int unit) {
			switch (unit) {
				case 1: return "nghìn";//strfmt(" %1 ", "@NNC215"); // " nghin ";//215
				case 2: return "triệu";//strfmt(" %1 ", "@NNC216");//" trieu ";//216
				case 3: return "tỷ";//strfmt(" %1 ", "@NNC217");//" ty ";//217
				default: return "";
			}
		}



		public static string VnNumber(this long number) {
			var result = String.Empty;

			var text = number.ToString();
			int unit = 0;
			while (text.Length > 12) {
				if (result.Length > 0 && !result.EndsWith(" ")) result += " ";
				result += VnUnit(unit) + MultyNumber(text.Substring(text.Length - 12), 12, 0);
				text = text.Substring(0, text.Length - 12);
				unit++;
				//if (unit > 3) unit = 0;
			}

			if (text.Length > 0) {
				if (result.Length > 0 && !result.EndsWith(" ")) result += " ";
				result = MultyNumber(text, text.Length, unit) + " " + result;
			}
			if(result.Length>0) {
				var first = result[0];
				result = first.ToString().ToUpper() + result.Substring(1);
			}
			return result;
		}
	}
}
